1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.hiprenderer.backend.gl.glshader; 12 version(GLES30) 13 { 14 enum shaderVersion = "#version 300 es"; 15 enum floatPrecision = "precision mediump float;"; 16 // enum floatPrecision = ""; 17 } 18 else version(GLES20) 19 { 20 enum shaderVersion = "#version 100"; 21 enum floatPrecision = "precision mediump float;"; 22 } 23 else 24 { 25 enum shaderVersion = "#version 330 core"; 26 enum floatPrecision = ""; 27 } 28 29 version(OpenGL): 30 import hip.api.renderer.texture; 31 import hip.hiprenderer.backend.gl.glrenderer; 32 import hip.hiprenderer.shader; 33 import hip.hiprenderer.renderer; 34 import hip.hiprenderer.shader.shadervar; 35 import hip.util.conv; 36 import hip.util.format: fastUnsafeCTFEFormat, format; 37 import hip.error.handler; 38 39 40 41 class Hip_GL3_FragmentShader : FragmentShader 42 { 43 uint shader; 44 private static string getBaseFragment() 45 { 46 __gshared string baseShader; 47 if(baseShader is null) 48 { 49 string defs; 50 version(WebAssembly) defs~= "#define WASM\n"; 51 version(PSVita) defs~= "#define PSVITA\n"; 52 baseShader = shaderVersion~"\n"~floatPrecision~"\n"~defs ~ getTexture2DDefine; 53 54 } 55 return baseShader; 56 } 57 private static string getTexture2DDefine() 58 { 59 return 60 `#ifdef WASM 61 #define TEXTURE_2D texture2D 62 #elif defined(PSVITA) 63 #define TEXTURE_2D texture2D 64 #else 65 #define TEXTURE_2D texture 66 #endif`; 67 } 68 override final string getDefaultFragment() 69 { 70 return getBaseFragment~q{ 71 72 uniform vec4 globalColor; 73 in vec4 vertexColor; 74 in vec2 tex_uv; 75 uniform sampler2D tex1; 76 out vec4 outPixelColor; 77 78 void main() 79 { 80 outPixelColor = vertexColor*globalColor*TEXTURE_2D(tex1, tex_uv); 81 } 82 }; 83 } 84 override final string getFrameBufferFragment() 85 { 86 return getBaseFragment~q{ 87 88 in vec2 inTexST; 89 uniform sampler2D uBufferTexture; 90 uniform vec4 uColor; 91 out vec4 outPixelColor; 92 93 void main() 94 { 95 vec4 col = TEXTURE_2D(uBufferTexture, inTexST); 96 float grey = (col.r+col.g+col.b)/3.0; 97 outPixelColor = grey * uColor; 98 } 99 }; 100 } 101 102 version(GLES20) //They are very different, so, better to keep them separate 103 { 104 override final string getSpriteBatchFragment() 105 { 106 int sup = HipRenderer.getMaxSupportedShaderTextures(); 107 string textureSlotSwitchCase; 108 if(sup == 1) textureSlotSwitchCase = "gl_FragColor = TEXTURE_2D(uTex[0], inTexST)*inVertexColor*uBatchColor;\n"; 109 else 110 { 111 for(int i = 0; i < sup; i++) 112 { 113 string strI = to!string(i); 114 if(i != 0) 115 textureSlotSwitchCase~="\t\t\t\telse "; 116 textureSlotSwitchCase~="if(texId == "~strI~")"~ 117 "{gl_FragColor = TEXTURE_2D(uTex["~strI~"], inTexST)*inVertexColor*uBatchColor;}\n"; 118 } 119 } 120 textureSlotSwitchCase~="}\n"; 121 enum shaderSource = q{ 122 uniform vec4 uBatchColor; 123 124 varying vec4 inVertexColor; 125 varying vec2 inTexST; 126 varying float inTexID; 127 128 void main() 129 }; 130 131 132 return getBaseFragment~format!q{ 133 uniform sampler2D uTex[%s];}(sup)~ 134 shaderSource~ 135 "{"~q{ 136 int texId = int(inTexID); 137 }~ textureSlotSwitchCase; 138 } 139 } 140 else 141 { 142 override final string getSpriteBatchFragment() 143 { 144 int sup = HipRenderer.getMaxSupportedShaderTextures(); 145 //Push the line breaks for easier debugging on gpu debugger 146 string textureSlotSwitchCase = "switch(texId)\n{\n"; 147 for(int i = 0; i < sup; i++) 148 { 149 string strI = to!string(i); 150 textureSlotSwitchCase~="case "~strI~": "~ 151 "\t\toutPixelColor = TEXTURE_2D(uTex["~strI~"], inTexST)*inVertexColor*uBatchColor;break;\n"; 152 } 153 textureSlotSwitchCase~="}\n"; 154 155 enum shaderSource = q{ 156 157 uniform vec4 uBatchColor; 158 159 in vec4 inVertexColor; 160 in vec2 inTexST; 161 in float inTexID; 162 163 out vec4 outPixelColor; 164 void main() 165 }; 166 return getBaseFragment~format!q{ 167 uniform sampler2D uTex[%s];}(sup)~ 168 shaderSource~ 169 "{"~q{ 170 int texId = int(inTexID); 171 } ~textureSlotSwitchCase~ 172 "}"; 173 // outPixelColor = texture(uTex[texId], inTexST)* inVertexColor * uBatchColor; 174 // outPixelColor = vec4(texId, texId, texId, 1.0)* inVertexColor * uBatchColor; 175 } 176 177 } 178 179 180 override final string getGeometryBatchFragment() 181 { 182 version(GLES20) 183 { 184 enum attr1 = q{varying}; 185 enum outputPixelVar = q{}; 186 enum outputAssignment = q{gl_FragColor}; 187 } 188 else 189 { 190 enum attr1 = q{in}; 191 enum outputPixelVar = q{out vec4 outPixelColor;}; 192 enum outputAssignment = q{outPixelColor}; 193 } 194 enum shaderSource = q{ 195 uniform vec4 uGlobalColor; 196 %s vec4 inVertexColor; 197 %s 198 199 void main() 200 { 201 %s = inVertexColor * uGlobalColor; 202 } 203 }.fastUnsafeCTFEFormat(attr1, outputPixelVar, outputAssignment); 204 return getBaseFragment~shaderSource; 205 } 206 207 override final string getBitmapTextFragment() 208 { 209 version(GLES20) 210 { 211 enum attr1 = q{varying}; 212 enum outputPixelVar = q{}; 213 enum outputAssignment = q{gl_FragColor}; 214 } 215 else 216 { 217 enum attr1 = q{in}; 218 enum outputPixelVar = q{out vec4 outPixelColor;}; 219 enum outputAssignment = q{outPixelColor}; 220 } 221 enum shaderSource = q{ 222 223 224 uniform vec4 uColor; 225 uniform sampler2D uTex; 226 %s vec2 inTexST; 227 %s 228 229 void main() 230 { 231 float r = TEXTURE_2D(uTex, inTexST).r; 232 %s = vec4(r,r,r,r)*uColor; 233 } 234 }.fastUnsafeCTFEFormat(attr1, outputPixelVar, outputAssignment); 235 return getBaseFragment~shaderSource; 236 } 237 } 238 class Hip_GL3_VertexShader : VertexShader 239 { 240 uint shader; 241 242 override final string getDefaultVertex() 243 { 244 return shaderVersion~"\n"~floatPrecision~"\n"~q{ 245 246 layout (location = 0) in vec3 position; 247 layout (location = 1) in vec4 color; 248 layout (location = 2) in vec2 texCoord; 249 uniform mat4 proj; 250 251 252 out vec4 vertexColor; 253 out vec2 tex_uv; 254 255 void main() 256 { 257 gl_Position = proj*vec4(position, 1.0); 258 vertexColor = color; 259 tex_uv = texCoord; 260 } 261 }; 262 } 263 override final string getFrameBufferVertex() 264 { 265 return shaderVersion~"\n"~floatPrecision~"\n"~q{ 266 267 layout (location = 0) in vec2 vPosition; 268 layout (location = 1) in vec2 vTexST; 269 270 out vec2 inTexST; 271 272 void main() 273 { 274 gl_Position = vec4(vPosition, 0.0, 1.0); 275 inTexST = vTexST; 276 } 277 }; 278 } 279 override final string getSpriteBatchVertex() 280 { 281 version(GLES20) //`in` representation in GLES 20 is `attribute`` 282 { 283 enum attr1 = q{attribute}; 284 enum attr2 = q{attribute}; 285 enum attr3 = q{attribute}; 286 enum attr4 = q{attribute}; 287 enum out1 = q{varying}; 288 enum out2 = q{varying}; 289 enum out3 = q{varying}; 290 } 291 else 292 { 293 enum attr1 = q{layout (location = 0) in}; 294 enum attr2 = q{layout (location = 1) in}; 295 enum attr3 = q{layout (location = 2) in}; 296 enum attr4 = q{layout (location = 3) in}; 297 enum out1 = q{out}; 298 enum out2 = q{out}; 299 enum out3 = q{out}; 300 } 301 enum shaderSource = q{ 302 %s vec3 vPosition; 303 %s vec4 vColor; 304 %s vec2 vTexST; 305 %s float vTexID; 306 307 uniform mat4 uProj; 308 uniform mat4 uModel; 309 uniform mat4 uView; 310 311 %s vec4 inVertexColor; 312 %s vec2 inTexST; 313 %s float inTexID; 314 315 void main() 316 { 317 gl_Position = uProj*uView*uModel*vec4(vPosition, 1.0); 318 inVertexColor = vColor; 319 inTexST = vTexST; 320 inTexID = vTexID; 321 } 322 }.fastUnsafeCTFEFormat(attr1, attr2, attr3, attr4, out1, out2, out3); 323 return shaderVersion~"\n"~floatPrecision~"\n"~shaderSource; 324 } 325 override final string getGeometryBatchVertex() 326 { 327 version(GLES20) 328 { 329 enum attr1 = q{attribute}; 330 enum attr2 = q{attribute}; 331 enum out1 = q{varying}; 332 } 333 else 334 { 335 enum attr1 = q{layout (location = 0) in}; 336 enum attr2 = q{layout (location = 1) in}; 337 enum out1 = q{out}; 338 } 339 340 enum shaderSource = q{ 341 342 %s vec3 vPosition; 343 %s vec4 vColor; 344 345 uniform mat4 uProj; 346 uniform mat4 uModel; 347 uniform mat4 uView; 348 349 %s vec4 inVertexColor; 350 351 void main() 352 { 353 gl_Position = uProj*uView*uModel*vec4(vPosition, 1.0); 354 inVertexColor = vColor; 355 } 356 }.fastUnsafeCTFEFormat(attr1, attr2, out1); 357 return shaderVersion~"\n"~floatPrecision~"\n"~shaderSource; 358 } 359 360 override final string getBitmapTextVertex() 361 { 362 version(GLES20) 363 { 364 enum attr1 = q{attribute}; 365 enum attr2 = q{attribute}; 366 enum out1 = q{varying}; 367 } 368 else 369 { 370 enum attr1 = q{layout (location = 0) in}; 371 enum attr2 = q{layout (location = 1) in}; 372 enum out1 = q{out}; 373 } 374 enum shaderSource = q{ 375 376 %s vec2 vPosition; 377 %s vec2 vTexST; 378 379 uniform mat4 uModel; 380 uniform mat4 uView; 381 uniform mat4 uProj; 382 383 %s vec2 inTexST; 384 385 void main() 386 { 387 gl_Position = uProj * uView * uModel * vec4(vPosition, 1.0, 1.0); 388 inTexST = vTexST; 389 } 390 }.fastUnsafeCTFEFormat(attr1, attr2, out1); 391 return shaderVersion~"\n"~floatPrecision~"\n"~shaderSource; 392 } 393 } 394 class Hip_GL3_ShaderProgram : ShaderProgram 395 { 396 bool isUsingUbo; 397 uint program; 398 protected HipBlendFunction blendSrc = HipBlendFunction.CONSTANT_COLOR, blendDst = HipBlendFunction.CONSTANT_COLOR; 399 protected HipBlendEquation blendEq = HipBlendEquation.DISABLED; 400 } 401 402 403 GLenum getGLBlendFunction(HipBlendFunction func) 404 { 405 final switch(func) with(HipBlendFunction) 406 { 407 case ZERO: return GL_ZERO; 408 case ONE: return GL_ONE; 409 case SRC_COLOR: return GL_SRC_COLOR; 410 case ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR; 411 case DST_COLOR: return GL_DST_COLOR; 412 case ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR; 413 case SRC_ALPHA: return GL_SRC_ALPHA; 414 case ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA; 415 case DST_ALPHA: return GL_DST_ALPHA; 416 case ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; 417 case CONSTANT_COLOR: return GL_CONSTANT_COLOR; 418 case ONE_MINUS_CONSTANT_COLOR: return GL_ONE_MINUS_CONSTANT_COLOR; 419 case CONSTANT_ALPHA: return GL_CONSTANT_ALPHA; 420 case ONE_MINUS_CONSTANT_ALPHA: return GL_ONE_MINUS_CONSTANT_ALPHA; 421 } 422 } 423 GLenum getGLBlendEquation(HipBlendEquation eq) 424 { 425 final switch(eq) with (HipBlendEquation) 426 { 427 case DISABLED: return GL_FUNC_ADD; 428 case ADD: return GL_FUNC_ADD; 429 case SUBTRACT: return GL_FUNC_SUBTRACT; 430 case REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT; 431 case MIN: return GL_MIN; 432 case MAX: return GL_MAX; 433 } 434 } 435 class Hip_GL_ShaderImpl : IShader 436 { 437 import hip.util.data_structures:Pair; 438 protected ShaderVariablesLayout[] layouts; 439 FragmentShader createFragmentShader() 440 { 441 Hip_GL3_FragmentShader fs = new Hip_GL3_FragmentShader(); 442 fs.shader = glCreateShader(GL_FRAGMENT_SHADER); 443 HipRenderer.exitOnError(); 444 return fs; 445 } 446 447 VertexShader createVertexShader() 448 { 449 Hip_GL3_VertexShader vs = new Hip_GL3_VertexShader(); 450 vs.shader = glCreateShader(GL_VERTEX_SHADER); 451 HipRenderer.exitOnError(); 452 return vs; 453 } 454 ShaderProgram createShaderProgram() 455 { 456 Hip_GL3_ShaderProgram prog = new Hip_GL3_ShaderProgram(); 457 prog.program = glCreateProgram(); 458 HipRenderer.exitOnError(); 459 return prog; 460 } 461 bool compileShader(GLuint shaderID, string shaderSource) 462 { 463 shaderSource~="\0"; 464 char* source = cast(char*)shaderSource.ptr; 465 glCall(() =>glShaderSource(shaderID, 1, &source, cast(GLint*)null)); 466 glCall(() =>glCompileShader(shaderID)); 467 int success; 468 469 glCall(() => glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success)); 470 if(ErrorHandler.assertErrorMessage(success==true, "Shader compilation error", "Compilation failed")) 471 { 472 import core.stdc.stdlib; 473 char[] infoLog; 474 version(WebAssembly) 475 { 476 { 477 GLint length = 0; 478 ubyte* temp = glCall(() => wglGetShaderInfoLog(shaderID)); 479 length = *cast(GLint*)temp; 480 infoLog = cast(char[])temp[size_t.sizeof..+size_t.sizeof + length]; 481 } 482 } 483 else 484 { 485 { 486 GLint length = 0; 487 glCall(() => glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &length)); 488 infoLog = cast(char[])malloc(length)[0..length]; 489 glCall(() =>glGetShaderInfoLog(shaderID, length, &length, infoLog.ptr)); 490 } 491 } 492 ErrorHandler.showErrorMessage("Error on shader source: ", shaderSource); 493 ErrorHandler.showErrorMessage("Compilation error:", cast(string)(infoLog)); 494 version(WebAssembly) 495 free(infoLog.ptr - GLint.sizeof); //Remember that the pointer started in length. 496 else 497 free(infoLog.ptr); 498 } 499 return success==true; 500 } 501 bool compileShader(VertexShader vs, string shaderSource) 502 { 503 return compileShader((cast(Hip_GL3_VertexShader)vs).shader, shaderSource); 504 } 505 bool compileShader(FragmentShader fs, string shaderSource) 506 { 507 return compileShader((cast(Hip_GL3_FragmentShader)fs).shader, shaderSource); 508 } 509 510 bool linkProgram(ref ShaderProgram program, VertexShader vs, FragmentShader fs) 511 { 512 uint prog = (cast(Hip_GL3_ShaderProgram)program).program; 513 514 glCall(() =>glAttachShader(prog, (cast(Hip_GL3_VertexShader)vs).shader)); 515 glCall(() =>glAttachShader(prog, (cast(Hip_GL3_FragmentShader)fs).shader)); 516 glCall(() =>glLinkProgram(prog)); 517 518 int success; 519 char[512] infoLog; 520 521 glCall(() =>glGetProgramiv(prog, GL_LINK_STATUS, &success)); 522 523 if(ErrorHandler.assertErrorMessage(success==true, "Shader linking error", "Linking failed")) 524 { 525 glCall(() => glGetProgramInfoLog(prog, 512, null, infoLog.ptr)); 526 ErrorHandler.showErrorMessage("Linking error: ", cast(string)(infoLog)); 527 } 528 529 return success==true; 530 } 531 int getId(ref ShaderProgram prog, string name) 532 { 533 int varID = glCall(() =>glGetUniformLocation((cast(Hip_GL3_ShaderProgram)prog).program, cast(char*)name.ptr)); //Immutable anyway 534 if(varID < 0) 535 { 536 ErrorHandler.showErrorMessage("Uniform not found", 537 "Variable named '"~name~"' does not exists in shader "~prog.name); 538 } 539 return varID; 540 } 541 542 543 /** 544 * params: 545 * layoutIndex: The layout index defined on shader 546 * valueAmount: How many values using, for 3 vertices, you can use 3 547 * dataType: Which data type to send 548 * normalize: If it will normalize 549 * stride: Target value amount in bytes, for instance, vec3 is float.sizeof*3 550 * offset: It will be calculated for each value index 551 * 552 */ 553 void sendVertexAttribute(uint layoutIndex, int valueAmount, uint dataType, bool normalize, uint stride, int offset) 554 { 555 glCall(() =>glVertexAttribPointer(layoutIndex, valueAmount, dataType, normalize, stride, cast(void*)offset)); 556 glCall(() =>glEnableVertexAttribArray(layoutIndex)); 557 } 558 559 private __gshared Hip_GL_ShaderImpl boundShader; 560 private __gshared HipBlendFunction currSrc, currDst; 561 private __gshared HipBlendEquation currEq; 562 private __gshared blendingEnabled = false; 563 564 public void setBlending(ShaderProgram prog, HipBlendFunction src, HipBlendFunction dst, HipBlendEquation eq) 565 { 566 Hip_GL3_ShaderProgram p = cast(Hip_GL3_ShaderProgram)prog; 567 p.blendSrc = src; 568 p.blendDst = dst; 569 p.blendEq = eq; 570 } 571 572 void bind(ShaderProgram program) 573 { 574 if(boundShader !is this) 575 { 576 Hip_GL3_ShaderProgram p = cast(Hip_GL3_ShaderProgram)program; 577 if(p.blendEq == HipBlendEquation.DISABLED) 578 { 579 if(blendingEnabled) 580 { 581 glCall(() => glDisable(GL_BLEND)); 582 blendingEnabled = false; 583 } 584 } 585 else 586 { 587 if(!blendingEnabled) 588 { 589 glCall(() => glEnable(GL_BLEND)); 590 blendingEnabled = true; 591 } 592 if(currEq != p.blendEq) 593 { 594 currEq = p.blendEq; 595 glCall(() => glBlendEquation(getGLBlendEquation(p.blendEq))); 596 } 597 if(currSrc != p.blendSrc || currDst != p.blendDst) 598 { 599 currSrc = p.blendSrc; 600 currDst = p.blendDst; 601 glCall(() => glBlendFunc(getGLBlendFunction(p.blendSrc), getGLBlendFunction(p.blendDst))); 602 } 603 } 604 glCall(() =>glUseProgram(p.program)); 605 boundShader = this; 606 } 607 } 608 void unbind(ShaderProgram program) 609 { 610 if(boundShader is this) 611 { 612 glCall(() =>glUseProgram(0)); 613 boundShader = null; 614 } 615 } 616 617 void sendVars(ref ShaderProgram prog, ShaderVariablesLayout[string] layouts) 618 { 619 foreach(ShaderVariablesLayout l; layouts) 620 { 621 foreach (ref ShaderVarLayout v; l.variables) 622 { 623 if(!v.sVar.isDirty) 624 continue; 625 int id = getId(prog, v.sVar.name); 626 final switch(v.sVar.type) with(UniformType) 627 { 628 case boolean: 629 glCall(() => glUniform1i(id, v.sVar.get!bool)); 630 break; 631 case integer: 632 glCall(() => glUniform1i(id, v.sVar.get!int)); 633 break; 634 case integer_array: 635 int[] temp = v.sVar.get!(int[]); 636 glCall(() =>glUniform1iv(id, cast(int)temp.length, temp.ptr)); 637 break; 638 case uinteger: 639 glCall(() =>glUniform1ui(id, v.sVar.get!uint)); 640 break; 641 case uinteger_array: 642 uint[] temp = v.sVar.get!(uint[]); 643 glCall(() =>glUniform1uiv(id, cast(int)temp.length, temp.ptr)); 644 break; 645 case floating: 646 glCall(() =>glUniform1f(id, v.sVar.get!float)); 647 break; 648 case floating2: 649 float[2] temp = v.sVar.get!(float[2]); 650 glCall(() =>glUniform2f(id, temp[0], temp[1])); 651 break; 652 case floating3: 653 float[3] temp = v.sVar.get!(float[3]); 654 glCall(() =>glUniform3f(id, temp[0], temp[1], temp[2])); 655 break; 656 case floating4: 657 float[4] temp = v.sVar.get!(float[4]); 658 glCall(() =>glUniform4f(id, temp[0], temp[1], temp[2], temp[3])); 659 break; 660 case floating2x2: 661 glCall(() => glUniformMatrix2fv(id, 1, GL_FALSE, cast(float*)v.sVar.get!(float[4]).ptr)); 662 break; 663 case floating3x3: 664 glCall(() =>glUniformMatrix3fv(id, 1, GL_FALSE, cast(float*)v.sVar.get!(float[9]).ptr)); 665 break; 666 case floating4x4: 667 glCall(() => glUniformMatrix4fv(id, 1, GL_FALSE, cast(float*)v.sVar.get!(float[16]).ptr)); 668 break; 669 case floating_array: 670 float[] temp = v.sVar.get!(float[]); 671 glCall(() => glUniform1fv(id, cast(int)temp.length, temp.ptr)); 672 break; 673 case texture_array: 674 GLint[] temp = v.sVar.get!(GLint[]); 675 glCall(() => glUniform1iv(id, cast(int)temp.length, cast(int*)temp.ptr)); 676 break; 677 case none:break; 678 } 679 v.sVar.isDirty = false; 680 } 681 } 682 683 } 684 685 bool setShaderVar(ShaderVar* sv, ShaderProgram prog, void* value) 686 { 687 ///Optimization for not allocating when inside loops. 688 __gshared int[] temp; 689 switch(sv.type) with(UniformType) 690 { 691 case texture_array: 692 { 693 IHipTexture[] textures = *cast(IHipTexture[]*)value; 694 if(textures.length > temp.length) 695 temp.length = textures.length; 696 int length = cast(int)textures.length; 697 foreach(i; 0..length) 698 temp[i] = i; 699 sv.set(temp, false); 700 return true; 701 } 702 default: return false; 703 } 704 } 705 706 void bindArrayOfTextures(ref ShaderProgram prog, IHipTexture[] textures, string varName) 707 { 708 bool shouldControlBind = boundShader !is this; 709 710 if(shouldControlBind) 711 bind(prog); 712 713 foreach(int i; 0..cast(int)textures.length) 714 textures[i].bind(i); 715 if(shouldControlBind) 716 unbind(prog); 717 } 718 void createVariablesBlock(ref ShaderVariablesLayout layout) 719 { 720 if(layout.hint & ShaderHint.GL_USE_BLOCK) 721 ErrorHandler.assertExit(false, "Use HipGL3 for Uniform Block support."); 722 } 723 724 void deleteShader(FragmentShader* _fs) 725 { 726 auto fs = cast(Hip_GL3_FragmentShader)*_fs; 727 glCall(() => glDeleteShader(fs.shader)); fs.shader = 0; 728 } 729 void deleteShader(VertexShader* _vs) 730 { 731 auto vs = cast(Hip_GL3_VertexShader)*_vs; 732 glCall(() => glDeleteShader(vs.shader)); vs.shader = 0; 733 } 734 void dispose(ref ShaderProgram prog) 735 { 736 Hip_GL3_ShaderProgram p = cast(Hip_GL3_ShaderProgram)prog; 737 glCall(() => glDeleteProgram(p.program)); 738 } 739 void onRenderFrameEnd(ShaderProgram program){} 740 } 741 742 743 version(HipGL3) class Hip_GL3_ShaderImpl : Hip_GL_ShaderImpl 744 { 745 import hip.util.data_structures:Pair; 746 protected Pair!(ShaderVariablesLayout, uint)[] ubos; 747 748 override int getId(ref ShaderProgram prog, string name) 749 { 750 // auto glProg = cast(Hip_GL3_ShaderProgram)prog; 751 //if(glProg.isUsingUbo) 752 // return getUboId() 753 //else 754 return super.getId(prog, name); 755 } 756 757 override void createVariablesBlock(ref ShaderVariablesLayout layout) 758 { 759 if(layout.hint & ShaderHint.GL_USE_BLOCK) 760 { 761 uint ubo; 762 glCall(() => glGenBuffers(1, &ubo)); 763 glCall(() => glBindBuffer(GL_UNIFORM_BUFFER, ubo)); 764 glCall(() => glBufferData(GL_UNIFORM_BUFFER, layout.getLayoutSize(), null, GL_DYNAMIC_DRAW)); 765 glCall(() => glBindBuffer(GL_UNIFORM_BUFFER, 0)); 766 ubos~= Pair!(ShaderVariablesLayout, uint)(layout, ubo); 767 } 768 } 769 protected uint getUboId(ref Pair!(ShaderVariablesLayout, int) ubo, string name) 770 { 771 return glCall(() =>glGetUniformBlockIndex(ubo.b, cast(char*)name.ptr)); 772 } 773 protected void bindUbo(ref Pair!(ShaderVariablesLayout, int) ubo, int index = 0) 774 { 775 glCall(() =>glBindBufferBase(GL_UNIFORM_BUFFER, index, ubo.second)); 776 } 777 protected void updateUbo(ref Pair!(ShaderVariablesLayout, int) ubo) 778 { 779 import core.stdc.string; 780 glCall(() =>glBindBuffer(GL_UNIFORM_BUFFER, ubo.b)); 781 GLvoid* ptr = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY); 782 memcpy(ptr, ubo.a.getBlockData(), ubo.a.getLayoutSize()); 783 glCall(() => glUnmapBuffer(GL_UNIFORM_BUFFER)); 784 glCall(() => glBindBuffer(GL_UNIFORM_BUFFER, 0)); 785 } 786 787 788 789 override void sendVars(ref ShaderProgram prog, ShaderVariablesLayout[string] layouts) 790 { 791 Hip_GL3_ShaderProgram glProg = cast(Hip_GL3_ShaderProgram)prog; 792 if(!glProg.isUsingUbo) 793 { 794 super.sendVars(prog, layouts); 795 return; 796 } 797 assert(false, "UBO binding is still not in use."); 798 } 799 800 override void dispose(ref ShaderProgram prog) 801 { 802 foreach (ub; ubos) 803 glCall(() => glDeleteBuffers(1, &ub.b)); 804 ubos.length = 0; 805 super.dispose(prog); 806 } 807 }